/*
  (C) 2005 Adam D. Bradley and Michael Ocean

  This program is free software; you can redistribute it and/or
  modify it under the terms of Version 2 of the GNU General Public 
  License.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package step;

import snobject.snObject;
import snobject.snObjectArgList;
import step.exceptions.ResourceUnavailableException;
import sxe.core.EvaluationFailureReasons;

public abstract class FunctionWrapper
{
    public abstract snObject Call(snObjectArgList argv) throws 
    	EvaluationFailure, 
    	ClassCastException,
    	ArrayIndexOutOfBoundsException,
    	ResourceUnavailableException;

    public final snObject Call(ExpNode n) throws EvaluationFailure {
    	expnode = n;
    	snObject args[] = new snObject[n.children.length];
		int i;
		for (i=0 ; i<n.children.length ; i++) {
			    args[i] = n.GetInput(i);
		}
		snObject snoRet = null;
		try{
			snoRet = Call(new snObjectArgList(args));
		} 
		/* Any exception is probably fatal.  ClassCast and ArrayIndex
		 * imply a SNAFU/STEP programmer error. EvaluationFailure 
		 * implies some snBench programmer initiated internal 
		 * failure in the opcode implentation.  Finally catching
		 * a super-type Exception implies something odd happened 
		 * in the implementation that was unexpected to the original
		 * programmer (as it was not wrapped in an EvaluationFailure).
		 * In all cases the calling function will mark this node
		 * (subtree) for pending deletion. */
		catch(EvaluationFailure e) {
			System.err.println("Evaluation failure within function :" + expnode.Opcode);
			e.printStackTrace();
			throw e;
		} catch(ResourceUnavailableException e){
			System.err.println("Casting failure with parameter to function :" + expnode.Opcode);
			e.printStackTrace();
			throw new EvaluationFailure(expnode,EvaluationFailureReasons.RESOURCE_UNAVAILABLE);
		}
		catch(ClassCastException ce) {
			System.err.println("Casting failure with parameter to function :" + expnode.Opcode);
			ce.printStackTrace();
			throw new EvaluationFailure(expnode,EvaluationFailureReasons.BAD_PARAMETER_TYPE);
		} catch(ArrayIndexOutOfBoundsException e) {
			System.err.println("Insufficient number of parameters to function :" + expnode.Opcode);
			e.printStackTrace();
			throw new EvaluationFailure(expnode,EvaluationFailureReasons.BAD_PARAMETER_COUNT);
		} catch(Exception e){
			System.err.println("Exception within Function :" + expnode.Opcode);
			e.printStackTrace();
			throw new EvaluationFailure(expnode,EvaluationFailureReasons.BAD_PARAMETER_EXECFAILED);
		}
		return snoRet;
    }
    
    protected ExpNode expnode;
    
    /* below are helper functions which may be used from within
     * Opcode implementations
     */
	public void CheckArgCount(snObjectArgList args, int i) throws EvaluationFailure{
		if(args.length()!=i)
			new EvaluationFailure(expnode,EvaluationFailureReasons.BAD_PARAMETER_COUNT);
	}

	public void CheckArgCountMin(snObjectArgList args, int i) throws EvaluationFailure{
		if(args.length()<i)
			throw new EvaluationFailure(expnode,EvaluationFailureReasons.BAD_PARAMETER_COUNT);
	}
}